//
// Created by Alex on 17/3/8.
//

#ifndef LIBCR_UTHREAD_H
#define LIBCR_UTHREAD_H

#include <cstring>
#include <printf.h>
#include <string>
#include <map>
#include "libcr.h"

#include "fcontext.h"

static const int kDefaultStackSize = 128 * 1024;
static const int kMaxStackSize = 1 * 1024 * 1024;

typedef void (*uthread_proc)(void *args);

struct stack_mem_t {
  uthread_t *m_occupy;
  int32_t m_stackSize;
  char *m_stackMem;

public:
  stack_mem_t(int32_t size);

  stack_mem_t();
};

struct uthread_t {
  fcontext_t m_context;
  fcontext_t m_scheduleContext;
  uthread_proc m_proc;
  void *m_arg;

  bool m_active;
  bool m_exit;
  bool m_isMain;
  bool m_isShareStack;
  bool m_enableHookSys;

  stack_mem_t *m_stack;

  char *m_saveStack;
  char *m_stackTop;
  size_t m_saveSize;

  uint64_t* m_spec;
  int m_specCount;
public:
  uthread_t(uthread_attr_t *attr, uthread_proc proc, void *arg);

  ~uthread_t();

  void yield();

  void resume();

  void* getSpec(int key);

  void* setSpec(int key, void *val);

private:
  void saveStack();

  void resumeStack();
};

struct share_stack_t {
  int32_t m_allocId;
  int32_t m_count;
  int32_t m_stackSize;
  stack_mem_t *m_stackInfo;
  char *m_mem;

  share_stack_t(int32_t count, int32_t stackSize);

  stack_mem_t *allocStack();

  ~share_stack_t();
};

#endif //LIBCR_UTHREAD_H
